module ReOrderBuffer(
	
	input			i_ROB_clk,
	input			i_ROB_enable,
	input			i_ROB_reset,
	//Stall
	output			o_ROB_Stall,
	//Load and Hit
	input	[31:0]	i_ROB_LoadPAddr,
	input	[5:0]	i_ROB_LoadReOrderNum,
	output			o_ROB_Hit,
	//EnQueue
	input	[64:0]	i_ROB_VIP1,
	output	[5:0]	o_ROB_ReOrderNum1,
	input	[64:0]	i_ROB_VIP2,
	output	[5:0]	o_ROB_ReOrderNum2,
	//Finished
	input			i_ROB_RRFinished1,
	input	[16:0]	i_ROB_RRF1_PRDes,
	input	[31:0]	i_ROB_RRF1_RFwbdata,
	input	[34:0]	i_ROB_RRF1_BRANCH,
	input	[7:0]	i_ROB_RRF1_EXCCODE,
	input	[5:0]	i_ROB_RRF1_ReOrderNum,
	
	input			i_ROB_RRFinished2,
	input	[16:0]	i_ROB_RRF2_PRDes,
	input	[31:0]	i_ROB_RRF2_RFwbdata,
	input	[34:0]	i_ROB_RRF2_BRANCH,
	input	[7:0]	i_ROB_RRF2_EXCCODE,
	input	[5:0]	i_ROB_RRF2_ReOrderNum,
	
	input			i_ROB_RRFinished3,
	input	[16:0]	i_ROB_RRF3_PRDes,
	input	[31:0]	i_ROB_RRF3_RFwbdata,
	input	[40:0]	i_ROB_RRF3_CP0w,
	input	[65:0]	i_ROB_RRF3_HILOw,
	input	[5:0]	i_ROB_RRF3_ReOrderNum,
	
	input			i_ROB_EXFinished4,
	input	[16:0]	i_ROB_EXF4_PRDes,
	input	[31:0]	i_ROB_EXF4_RFwbdata,
	input	[7:0]	i_ROB_EXF4_EXCCODE,
	input	[5:0]	i_ROB_EXF4_ReOrderNum,
	
	input			i_ROB_EXFinished5,
	input	[16:0]	i_ROB_EXF5_PRDes,
	input	[31:0]	i_ROB_EXF5_RFwbdata,
	input	[7:0]	i_ROB_EXF5_EXCCODE,
	input	[5:0]	i_ROB_EXF5_ReOrderNum,
	
	input			i_ROB_EXFinished6,
	input	[31:0]	i_ROB_EXF6_BadVAddr,
	input	[7:0]	i_ROB_EXF6_EXCCODE,
	input	[5:0]	i_ROB_EXF6_ReOrderNum,
	
	input			i_ROB_EXFinished7,
	input	[5:0]	i_ROB_EXF7_ReOrderNum,
	
	input			i_ROB_MMFinished8,
	input	[67:0]	i_ROB_MMF8_STORE,
	input	[7:0]	i_ROB_MMF8_EXCCODE,
	input	[5:0]	i_ROB_MMF8_ReOrderNum,
	
	input			i_ROB_LSFinished9,
	input	[16:0]	i_ROB_LSF9_PRDes,
	input	[31:0]	i_ROB_LSF9_RFwbdata,
	input	[5:0]	i_ROB_LSF9_ReOrderNum,
	
	//DeQueue --> CMOMIT
	output	[64:0]	o_ROB_CMT_A_VIP,		//{[64]valid, [63:32]Inst, [31:0]PC}
	output	[16:0]	o_ROB_CMT_A_PRDes,		////{[16:12]regdes, [11:6]pregdes, [5:0]ppregdes}
	output	[31:0]	o_ROB_CMT_A_RFwbdata,	//debug_wb_rf_wdata
	output	[34:0]	o_ROB_CMT_A_BRANCH,		//{[34]BranchEnable, [33:32]BranchTaken, [31:0]BranchTarget}					
	output	[67:0]	o_ROB_CMT_A_STORE,		//{[67]StoreEnable, [66:64]StoreSize, [63:32]StorePAddr, [31:0]StoreData}						
	output	[40:0]	o_ROB_CMT_A_CP0w,		//{[40]CP0wen, [39:35]CP0addr, [34:32]CP0sel, [31:0]CP0data}
	output	[65:0]	o_ROB_CMT_A_HILOw,		//{[65:64]HILOwen, [63:0]HILOwdata}
	output	[31:0]	o_ROB_CMT_A_BadVAddr,
	output	[7:0]	o_ROB_CMT_A_EXCCODE,
	output	[64:0]	o_ROB_CMT_B_VIP,		//{[64]valid, [63:32]Inst, [31:0]PC}
	output	[16:0]	o_ROB_CMT_B_PRDes,		////{[16:12]regdes, [11:6]pregdes, [5:0]ppregdes}
	output	[31:0]	o_ROB_CMT_B_RFwbdata,	//debug_wb_rf_wdata
	output	[34:0]	o_ROB_CMT_B_BRANCH,		//{[34]BranchEnable, [33:32]BranchTaken, [31:0]BranchTarget}					
	output	[67:0]	o_ROB_CMT_B_STORE,		//{[67]StoreEnable, [66:64]StoreSize, [63:32]StorePAddr, [31:0]StoreData}						
	output	[40:0]	o_ROB_CMT_B_CP0w,		//{[40]CP0wen, [39:35]CP0addr, [34:32]CP0sel, [31:0]CP0data}
	output	[65:0]	o_ROB_CMT_B_HILOw,		//{[65:64]HILOwen, [63:0]HILOwdata}
	output	[31:0]	o_ROB_CMT_B_BadVAddr,
	output	[7:0]	o_ROB_CMT_B_EXCCODE
	
);

	reg			valid[63:0];
	reg			finished[63:0];
	//follow
	reg	[63:0]	InstPC[63:0];
	reg	[16:0]	PRDes[63:0];
	reg	[31:0]	RFwbdata[63:0];
	reg	[34:0]	BRANCH[63:0];
	reg	[67:0]	STORE[63:0];
	reg	[31:0]	StorePAddr[63:0];//for LoadHit
	reg	[40:0]	CP0w[63:0];
	reg	[65:0]	HILOw[63:0];
	reg	[31:0]	BadVAddr[63:0];
	reg	[7:0]	EXCCODE[63:0];
	
	//Pointers
	reg		[5:0]	EnQueuePointer;
	reg		[5:0]	DeQueuePointer;
	wire	[5:0]	EnQueuePointer_1 = EnQueuePointer + 6'd1;
	wire	[5:0]	DeQueuePointer_1 = DeQueuePointer + 6'd1;
	
	//EnQueue
	wire	[63:0]	EmptyList;
	begin:	emptylist
		reg	[7:0]	tempI;
		for(tempI=8'd0; tempI<=8'd63; tempI=tempI+8'd1)
			assign	EmptyList[tempI[5:0]] = ~valid[tempI[5:0]];
	end
	wire	Empty = (EmptyList==32'hffff_ffff);
	
	assign	o_ROB_ReOrderNum1 = EnQueuePointer;
	assign	o_ROB_ReOrderNum2 = EnQueuePointer_1;
	
	assign	o_ROB_Stall = ~Empty && 
						(((DeQueuePointer==EnQueuePointer) && (i_ROB_VIP1[65] || i_ROB_VIP2[65]) ||
						  ((DeQueuePointer==EnQueuePointer+4'd1) && i_ROB_VIP1[65] && i_ROB_VIP2[65]));
						 
	//DeQueue
	wire	A_Ready = valid[DeQueuePointer] && finished[DeQueuePointer];
	wire	B_Ready = 1'b0;
	
	assign	o_ROB_CMT_A_VIP			= (A_Ready) ? {valid[DeQueuePointer], InstPC[DeQueuePointer]}: 65'd0:
	assign	o_ROB_CMT_A_PRDes		= (A_Ready) ? PRDes[DeQueuePointer]: 17'd0:
	assign	o_ROB_CMT_A_RFwbdata	= (A_Ready) ? RFwbdata[DeQueuePointer] : 32'd0;
	assign	o_ROB_CMT_A_BRANCH		= (A_Ready) ? BRANCH[DeQueuePointer] : 35'd0;
	assign	o_ROB_CMT_A_STORE		= (A_Ready) ? STORE[DeQueuePointer] : 68'd0;
	assign	o_ROB_CMT_A_CP0w		= (A_Ready) ? CP0w[DeQueuePointer] : 41'd0;
	assign	o_ROB_CMT_A_HILOw		= (A_Ready) ? HILOw[DeQueuePointer] : 66'd0;
	assign	o_ROB_CMT_A_BadVAddr	= (A_Ready) ? BadVAddr[DeQueuePointer] : 32'd0;
	assign	o_ROB_CMT_A_EXCCODE		= (A_Ready) ? EXCCODE[DeQueuePointer] : 8'd0;
	
	assign	o_ROB_CMT_B_VIP			= (B_Ready) ? {valid[DeQueuePointer_1], InstPC[DeQueuePointer_1]}: 65'd0:
	assign	o_ROB_CMT_B_PRDes		= (B_Ready) ? PRDes[DeQueuePointer_1]: 17'd0:
	assign	o_ROB_CMT_B_RFwbdata	= (B_Ready) ? RFwbdata[DeQueuePointer_1] : 32'd0;
	assign	o_ROB_CMT_B_BRANCH		= (B_Ready) ? BRANCH[DeQueuePointer_1] : 35'd0;
	assign	o_ROB_CMT_B_STORE		= (B_Ready) ? STORE[DeQueuePointer_1] : 68'd0;
	assign	o_ROB_CMT_B_CP0w		= (B_Ready) ? CP0w[DeQueuePointer_1] : 41'd0;
	assign	o_ROB_CMT_B_HILOw		= (B_Ready) ? HILOw[DeQueuePointer_1] : 66'd0;
	assign	o_ROB_CMT_B_BadVAddr	= (B_Ready) ? BadVAddr[DeQueuePointer_1] : 32'd0;
	assign	o_ROB_CMT_B_EXCCODE		= (B_Ready) ? EXCCODE[DeQueuePointer_1] : 8'd0;
	
	//LoadHit
	wire	[63:0]	LoadHit;
	begin:	loadhit
		reg	[7:0]	tempJ;
			for(tempJ=8'd0; tempJ<=8'd63; tempJ=tempJ+8'd1)
				assign	LoadHit[tempJ[5:0]] = (StorePAddr[tempJ[5:3]]==i_ROB_LoadPAddr);
	end
	assign o_ROB_Hit = (i_ROB_LoadReOrderNum==DeQueuePointer) ? 1'd0 : (LoadHit!=64'd0);
	
always @(posedge i_ROB_clk)
	begin
		if(i_ROB_reset)
			begin:	reset
				reg	[7:0]	tempK;
				for(tempK=8'd0; tempK<=8'd63; tempK=tempK+8'd1)
					begin
						valid[tempK[5:0]]		<= 1'd0;
						finished[tempK[5:0]]	<= 1'd0;
						InstPC[tempK[5:0]]		<= 64'd0;
						PRDes[tempK[5:0]]		<= 17'd0;
						RFwbdata[tempK[5:0]]	<= 32'd0;
						BRANCH[tempK[5:0]]		<= 35'd0;
						STORE[tempK[5:0]]		<= 68'd0;
						StorePAddr[tempK[5:0]]	<= 32'd0;//for LoadHit
						CP0w[tempK[5:0]]		<= 41'd0;
						HILOw[tempK[5:0]]		<= 66'd0;
						BadVAddr[tempK[5:0]]	<= 32'd0;
						EXCCODE[tempK[5:0]]		<= 8'd0;
						//Pointers
						DeQueuePointer	<= 6'd0;
						EnQueuePointer  <= 6'd0;
					end
			end
		else if(i_ROB_enable)
			begin
				if(rollback)
					begin:	rollback
						reg	[7:0]	tempK;
						for(tempK=8'd0; tempK<=8'd63; tempK=tempK+8'd1)
							begin
								valid[tempK[5:0]]		<= 1'd0;
								finished[tempK[5:0]]	<= 1'd0;
								InstPC[tempK[5:0]]		<= 64'd0;
								PRDes[tempK[5:0]]		<= 17'd0;
								RFwbdata[tempK[5:0]]	<= 32'd0;
								BRANCH[tempK[5:0]]		<= 35'd0;
								STORE[tempK[5:0]]		<= 68'd0;
								StorePAddr[tempK[5:0]]	<= 32'd0;//for LoadHit
								CP0w[tempK[5:0]]		<= 41'd0;
								HILOw[tempK[5:0]]		<= 66'd0;
								BadVAddr[tempK[5:0]]	<= 32'd0;
								EXCCODE[tempK[5:0]]		<= 8'd0;
								//Pointers
								DeQueuePointer	<= 6'd0;
								EnQueuePointer  <= 6'd0;
							end
					end
				else
					begin
		//--------------EnQueue
						if(~o_ROB_Stall && i_ROB_VIP1[65] && i_ROB_VIP2[65])
							begin
								valid[EnQueuePointer]		<= i_ROB_VIP1[64];
								InstPC[EnQueuePointer]		<= i_ROB_VIP1[63:0];
								valid[EnQueuePointer_1]		<= i_ROB_VIP2[64];
								InstPC[EnQueuePointer_1]	<= i_ROB_VIP2[63:0];
								//updata EnQueuePointer
								EnQueuePointer <= EnQueuePointer + 6'd2;
							end
						if(~o_ROB_Stall && i_ROB_VIP1[65] && ~i_ROB_VIP2[65])
							begin
								valid[EnQueuePointer]		<= i_ROB_VIP1[64];
								InstPC[EnQueuePointer]		<= i_ROB_VIP1[63:0];
								//updata EnQueuePointer
								EnQueuePointer <= EnQueuePointer + 6'd1;
							end
						if(~o_ROB_Stall && ~i_ROB_VIP1[65] && i_ROB_VIP2[65])
							begin
								valid[EnQueuePointer]		<= i_ROB_VIP2[64];
								InstPC[EnQueuePointer]		<= i_ROB_VIP2[63:0];
								//updata EnQueuePointer
								EnQueuePointer <= EnQueuePointer + 6'd1;
							end
		//--------------Finished
						if(i_ROB_RRFinished1)
							begin
								finished[i_ROB_RRF1_ReOrderNum] 	<= 1'd1;
								PRDes	[i_ROB_RRF1_ReOrderNum] 	<= i_ROB_RRF1_PRDes;
								RFwbdata[i_ROB_RRF1_ReOrderNum] 	<= i_ROB_RRF1_RFwbdata;
								BRANCH	[i_ROB_RRF1_ReOrderNum] 	<= i_ROB_RRF1_BRANCH;
								EXCCODE	[i_ROB_RRF1_ReOrderNum] 	<= i_ROB_RRF1_EXCCODE;
							end
						if(i_ROB_RRFinished2)
							begin
								finished[i_ROB_RRF2_ReOrderNum] 	<= 1'd1;
								PRDes	[i_ROB_RRF2_ReOrderNum] 	<= i_ROB_RRF2_PRDes;
								RFwbdata[i_ROB_RRF2_ReOrderNum] 	<= i_ROB_RRF2_RFwbdata;
								BRANCH	[i_ROB_RRF2_ReOrderNum] 	<= i_ROB_RRF2_BRANCH;
								EXCCODE	[i_ROB_RRF2_ReOrderNum] 	<= i_ROB_RRF2_EXCCODE;
							end
						if(i_ROB_RRFinished3)
							begin
								finished[i_ROB_RRF3_ReOrderNum] 	<= 1'd1;
								PRDes	[i_ROB_RRF3_ReOrderNum] 	<= i_ROB_RRF3_PRDes;
								RFwbdata[i_ROB_RRF3_ReOrderNum] 	<= i_ROB_RRF3_RFwbdata;
								CP0w	[i_ROB_RRF3_ReOrderNum] 	<= i_ROB_RRF3_CP0w;
								HILOw	[i_ROB_RRF3_ReOrderNum] 	<= i_ROB_RRF3_HILOw;
							end
						if(i_ROB_EXFinished4)
							begin
								finished[i_ROB_EXF4_ReOrderNum] <= 1'd1;
								PRDes	[i_ROB_EXF4_ReOrderNum]	<= i_ROB_EXF4_PRDes;
								RFwbdata[i_ROB_EXF4_ReOrderNum]	<= i_ROB_EXF4_RFwbdata;
								EXCCODE	[i_ROB_EXF4_ReOrderNum]	<= i_ROB_EXF4_EXCCODE;
							end
						if(i_ROB_EXFinished5)
							begin
								finished[i_ROB_EXF5_ReOrderNum] <= 1'd1;
								PRDes	[i_ROB_EXF5_ReOrderNum]	<= i_ROB_EXF5_PRDes;
								RFwbdata[i_ROB_EXF5_ReOrderNum]	<= i_ROB_EXF5_RFwbdata;
								EXCCODE	[i_ROB_EXF5_ReOrderNum]	<= i_ROB_EXF5_EXCCODE;
							end
						if(i_ROB_EXFinished6)
							begin
								finished[i_ROB_EXF6_ReOrderNum] <= 1'd1;
								BadVAddr[i_ROB_EXF6_ReOrderNum]	<= i_ROB_EXF6_BadVAddr;
								EXCCODE	[i_ROB_EXF6_ReOrderNum]	<= i_ROB_EXF6_EXCCODE;
							end
						if(i_ROB_EXFinished7)
							begin
								finished[i_ROB_EXF7_ReOrderNum] <= 1'd1;
							end
						if(i_ROB_MMFinished8)
							begin
								finished[i_ROB_MMF8_ReOrderNum] <= 1'd1;
								STORE	[i_ROB_MMF8_ReOrderNum]	<= i_ROB_MMF8_STORE,
								EXCCODE	[i_ROB_MMF8_ReOrderNum]	<= i_ROB_MMF8_EXCCODE;//tlb
								//for LoadHit
								StorePAddr[i_ROB_MMF8_ReOrderNum]<= i_ROB_MMF8_STORE[63:32];
							end
						if(i_ROB_LSFinished9)
							begin
								finished[i_ROB_LSF9_ReOrderNum] <= 1'd1;
								PRDes	[i_ROB_LSF9_ReOrderNum]	<= i_ROB_LSF9_PRDes,
								RFwbdata[i_ROB_LSF9_ReOrderNum]	<= i_ROB_LSF9_RFwbdata,
							end
		//--------------DeQueue
						if(A_Ready && B_Ready)
							begin
								valid[DeQueuePointer]		<= 1'd0;
								finished[DeQueuePointer]	<= 1'd0;
								InstPC[DeQueuePointer]		<= 64'd0;
								PRDes[DeQueuePointer]		<= 17'd0;
								RFwbdata[DeQueuePointer]	<= 32'd0;
								BRANCH[DeQueuePointer]		<= 35'd0;
								STORE[DeQueuePointer]		<= 68'd0;
								StorePAddr[DeQueuePointer]	<= 68'd0;//for LoadHit
								CP0w[DeQueuePointer]		<= 41'd0;
								HILOw[DeQueuePointer]		<= 66'd0;
								BadVAddr[DeQueuePointer]	<= 32'd0;
								EXCCODE[DeQueuePointer]		<= 8'd0;
								
								valid[DeQueuePointer_1]		<= 1'd0;
								finished[DeQueuePointer_1]	<= 1'd0;
								InstPC[DeQueuePointer_1]	<= 64'd0;
								PRDes[DeQueuePointer_1]		<= 17'd0;
								RFwbdata[DeQueuePointer_1]	<= 32'd0;
								BRANCH[DeQueuePointer_1]	<= 35'd0;
								STORE[DeQueuePointer_1]		<= 68'd0;
								StorePAddr[DeQueuePointer_1]<= 68'd0;//for LoadHit
								CP0w[DeQueuePointer_1]		<= 41'd0;
								HILOw[DeQueuePointer_1]		<= 66'd0;
								BadVAddr[DeQueuePointer_1]	<= 32'd0;
								EXCCODE[DeQueuePointer_1]	<= 8'd0;
								//updata DeQueuePointer
								DeQueuePointer <= DeQueuePointer + 6'd2;
							end
						if(A_Ready && ~B_Ready)
							begin
								valid[DeQueuePointer]		<= 1'd0;
								finished[DeQueuePointer]	<= 1'd0;
								InstPC[DeQueuePointer]		<= 64'd0;
								PRDes[DeQueuePointer]		<= 17'd0;
								RFwbdata[DeQueuePointer]	<= 32'd0;
								BRANCH[DeQueuePointer]		<= 35'd0;
								STORE[DeQueuePointer]		<= 68'd0;
								StorePAddr[DeQueuePointer]	<= 68'd0;//for LoadHit
								CP0w[DeQueuePointer]		<= 41'd0;
								HILOw[DeQueuePointer]		<= 66'd0;
								BadVAddr[DeQueuePointer]	<= 32'd0;
								EXCCODE[DeQueuePointer]		<= 8'd0;
								//updata DeQueuePointer
								DeQueuePointer <= DeQueuePointer + 6'd1;
							end
					end
			end
	end

endmodule